import * as THREE from 'three';
import vertexShader from './vertexShader.glsl';
import fragmentShader from './fragmentShader.glsl';
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
import { converColor } from '../index';
import { Tween, Easing } from '@tweenjs/tween.js';
export default class {
  config: any = {
    barConfig: {
      barType: 'rect',
      raiseTime: 1,
      scaleR: 1,
      scaleY: 1,
      size: 1,
      color: {
        color: '#f00',
        fillType: 'solid',
        colors: { start: '#f00', end: '#fff' }
      }
    },
    heightConfig: {
      selectedHeight: 10
    },
    baseConfig: {
      showLevel: 1
    }
  };
  selectedBar: any = null;
  lastBar: any = null;
  lightBars: any[] = [];
  animState = 0;
  barGroup = new THREE.Group();
  containethis: HTMLElement;
  srcLnglatToWorld: Function;
  data: any;
  camera: THREE.Camera;
  container: any;
  appearTween: any;
  constructor(e, i) {
    this.config = e.configuration.lightBar;
    this.srcLnglatToWorld = i.srcLnglatToWorld;
    this.data = e.data;
    this.container = i.mapContainer;
    this.camera = i.camera;
    this.appearTween = null;
    this.animState = 0;
    this.barGroup.name = 'barGroup';
    this.barGroup.layers.enable(1);
    this.barGroup.position.y = this.config.heightConfig.baseHeight;
    i.childrenGroup.add(this.barGroup);
    this.showData();
    // this.containethis.addEventListener('mousemove', this.handleMouseMove.bind(this), false);
  }
  getMatColor(e) {
    var n = converColor(e.color);
    var s = converColor(e.colors.end);
    var p = converColor(e.colors.start);
    const color1 = new THREE.Color(n.r, n.g, n.b);
    const color2 = new THREE.Color(s.r, s.g, s.b);
    const color3 = new THREE.Color(p.r, p.g, p.b);
    return {
      topOpacity: 'gradient' == e.fillType ? p.a : n.a,
      topColor: 'gradient' == e.fillType ? color3 : color1,
      bottomOpacity: 'gradient' == e.fillType ? s.a : n.a,
      bottomColor: 'gradient' == e.fillType ? color2 : color1
    };
  }
  initMaterial() {
    var { barType, color } = this.config.barConfig;
    var t = this.getMatColor(color);
    const uniforms = THREE.UniformsUtils.merge([
      THREE.ShaderLib.phong.uniforms,
      {
        bottomOpacity: { value: t.bottomOpacity },
        bottomColor: { value: t.bottomColor },
        topOpacity: { value: t.topOpacity },
        topColor: { value: t.topColor },
        opacity: { value: t.topOpacity }
      }
    ]);
    var mat1 = new THREE.ShaderMaterial({
      uniforms,
      vertexShader,
      fragmentShader,
      transparent: !0,
      depthTest: !1
    });
    mat1.lights = true;
    var mat2 = new THREE.MeshPhongMaterial({
      color: t.topColor,
      transparent: !0,
      opacity: t.topOpacity,
      depthTest: !1
    });
    return barType === 'rect' ? [mat1, mat1, mat2, mat1, mat1, mat1] : [mat1, mat2, mat1];
  }
  initBar(material, i) {
    const { barType, scaleR, scaleY, size } = this.config.barConfig;
    const radius = size * scaleR;
    const height = i * scaleY;
    var o: any = new THREE.CylinderGeometry(radius, radius, height, 50, 20);
    if ('rect' == barType) {
      o = new THREE.BoxGeometry(radius, height, 0.01, 50, 20);
    }
    var s = new THREE.Mesh(o, material);
    s.layers.enable(1);
    s.rotation.y = Math.PI / 4;
    s.renderOrder = 2e3;
    s.userData.visible = true;
    s.userData.enlarged = false;
    s.userData.height = i;
    s.userData.baseHeight = i / 2;
    s.position.y = i / 2;
    return s;
  }
  showData() {
    this.barGroup.children = [];
    for (var u = 0; u < this.data.length; u++) {
      var c = this.data[u];
      var h = this.srcLnglatToWorld([c.lng, c.lat]);
      var d = this.initBar(this.initMaterial(), c.count);
      d.position.x = h.x;
      d.position.z = -h.y;
      d.userData = { ...d.userData, ...c, index: u + 1 };
      this.barGroup.add(d);
      this.lightBars.push(d);
    }
    this.lightBars = this.lightBars.sort(function (e, t) {
      return t.userData.height - e.userData.height;
    });
    this.barGroup.scale.set(1, 0, 1);
    this.barAppearAnim();
  }
  barAppearAnim() {
    this.animState = 1;
    this.appearTween = new Tween([0]).to([1], 1500);
    this.appearTween.easing(Easing.Quadratic.InOut);
    this.appearTween.update(t => {
      this.barGroup.scale.set(1, t.scale, 1);
    });
    this.appearTween.complete(() => {
      this.animState = 0;
    });
  }
  initPlane(e, t) {
    this.getImgBgDiv(e, t);
  }
  getImgBgDiv(e, t) {
    var pe = document.createElement('div');
    var de = document.createElement('div');
    pe.appendChild(de);
    // 由于 THREE 上不存在 CSS2DObject 属性，需要单独引入 CSS2DRenderer 中的 CSS2DObject
    var fe = new CSS2DObject(pe);
    fe.position.y = e.userData.height / 2;
    e.userData.plane = fe;
    e.add(fe);
  }
  updateMaterials(e, t) {
    let color = this.getMatColor(this.config.baseConfig.sliderPassStyle.color);
    if ('none' == t) {
      color = this.getMatColor(this.config.barConfig.color);
    }
    const { bottomOpacity, topColor, topOpacity, bottomColor } = color;
    for (var s = 0; s < e.material.length; s++) {
      var l = e.material[s];
      if ('ShaderMaterial' == l.type) {
        l.uniforms.bottomColor.value = bottomColor;
        l.uniforms.bottomOpacity.value = bottomOpacity;
        l.uniforms.topColor.value = topColor;
        l.uniforms.topOpacity.value = topOpacity;
      } else {
        l.color = topColor;
      }
    }
  }
  handleMouseMove(e) {
    const { clientX, clientY } = e;
    const { top, left, width, height } = this.container.getBoundingClientRect();
    var u = new THREE.Vector2();
    u.x = ((clientX - left) / width) * 2 - 1;
    u.y = (-(clientY - top) / height) * 2 + 1;
    var i = new THREE.Raycaster();
    i.setFromCamera(u, this.camera);
    const c = i.intersectObjects(this.lightBars, true);
    if (c.length) {
      var h = c[0].object;
      var p = h.userData.plane;
      if (p && this.selectedBar) {
        this.selectedBar.userData.plane.element.style.display = 'none';
        this.updateMaterials(this.selectedBar, 'none');
        p.element.style.display = 'block';
        this.updateMaterials(h, 'block');
        this.selectedBar = h;
      }
    } else {
      if (this.selectedBar) {
        this.selectedBar.userData.plane.element.style.display = 'none';
        this.updateMaterials(this.selectedBar, 'none');
        this.selectedBar = null;
      }
    }
  }
  updateBarHeight(e, t) {
    t += this.config.heightConfig.selectedHeight;
    var n = this.lightBars.filter(t => t.userData.adcode == e)[0];
    if (n && this.lastBar && this.lastBar.position.y !== 0) {
      this.lastBar.position.y = this.lastBar.userData.baseHeight;
      n.position.y = n.userData.baseHeight + t;
      this.lastBar = n;
    }
  }
}
